#!/bin/sh

########################################################################
# This test checks changing target module in runtime.
# Usage: 
#   sh test.sh <target1_dir> <target2_dir>
#
# The target modules should be: <targetN_dir>/test_<targetN_dir>.ko
########################################################################
########################################################################
# A function to check prerequisites: whether the necessary files exist,
# etc.
########################################################################
checkPrereqs()
{
	#if test ! -f "${KEDR_MODULE}"; then
	#	printf "KEDR core module is missing: ${KEDR_MODULE}\n"
	#	exit 1
	#fi
	
	if test ! -f "${TARGET_MODULE1}"; then
		printf "Target module is missing: ${TARGET_MODULE1}\n"
		exit 1
	fi
	
	if test ! -f "${TARGET_MODULE2}"; then
		printf "Target module is missing: ${TARGET_MODULE2}\n"
		exit 1
	fi
	
	if test ! -f "${PAYLOAD_MODULE}"; then
		printf "Payload module is missing: ${PAYLOAD_MODULE}\n"
		exit 1
	fi
}

########################################################################
# Cleanup function
########################################################################
cleanupAll()
{
	cd "${WORK_DIR}"
	
	@LSMOD@ | grep "${TARGET_NAME1_ACTUAL}" > /dev/null 2>&1
	if test $? -eq 0; then
		@RMMOD@ "${TARGET_NAME1_ACTUAL}"
	fi
	
	@LSMOD@ | grep "${TARGET_NAME2_ACTUAL}" > /dev/null 2>&1
	if test $? -eq 0; then
		@RMMOD@ "${TARGET_NAME2_ACTUAL}"
	fi
	
	@LSMOD@ | grep "${PAYLOAD_NAME}" > /dev/null 2>&1
	if test $? -eq 0; then
		@RMMOD@ "${PAYLOAD_NAME}"
	fi
	
	@LSMOD@ | grep "@KEDR_CORE_NAME@" > /dev/null 2>&1
	if test $? -eq 0; then
		@RMMOD@ "@KEDR_CORE_NAME@"
	fi
}

########################################################################
# Check if the string contents of the target_* parameters of the payload
# match the expected ones.
# Usage:
#   checkOutputStrings <expectedLoad> <expectedUnload>
########################################################################
checkOutputStrings()
{
	if test $# -ne 2; then
		printf "checkOutputStrings(): incorrect number of arguments\n"
		cleanupAll
		exit 1
	fi

	expectedLoad="$1"
	expectedUnload="$2"

	resultLoadString=$(cat "${OUT_LOAD_PARAM}")
	resultUnloadString=$(cat "${OUT_UNLOAD_PARAM}")
	if test "t${resultLoadString}" != "t${expectedLoad}"; then
		printf "\"Load\" string should have been \"${expectedLoad}\" "
		printf "but it is \"${resultLoadString}\".\n"
		cleanupAll
		exit 1
	fi

	if test "t${resultUnloadString}" != "t${expectedUnload}"; then
		printf "\"Unload\" string should have been \"${expectedUnload}\" "
		printf "but it is \"${resultUnloadString}\".\n"
		cleanupAll
		exit 1
	fi
}

########################################################################
# doTest() - preform the actual testing
########################################################################
doTest()
{
	@KEDR_CORE_LOAD_COMMAND@ target_name="${TARGET_NAME1}" || exit 1

	@INSMOD@ "${PAYLOAD_MODULE}" \
		set_load_fn=1 \
		set_unload_fn=1
	if test $? -ne 0; then
		printf "Failed to load the payload module\n"
		cleanupAll
		exit 1
	fi

	EXPECTED_LOAD_STRING="${TARGET_NAME1_ACTUAL}"
	EXPECTED_UNLOAD_STRING="${TARGET_NAME1_ACTUAL}"

	OUT_LOAD_PARAM="/sys/module/${PAYLOAD_NAME}/parameters/target_load_name"
	if test ! -e "${OUT_LOAD_PARAM}"; then
		printf "Parameter file does not exist: ${OUT_LOAD_PARAM}\n"
		cleanupAll
		exit 1
	fi

	OUT_UNLOAD_PARAM="/sys/module/${PAYLOAD_NAME}/parameters/target_unload_name"
	if test ! -e "${OUT_UNLOAD_PARAM}"; then
		printf "Parameter file does not exist: ${OUT_UNLOAD_PARAM}\n"
		cleanupAll
		exit 1
	fi

	@INSMOD@ "${TARGET_MODULE1}"
	if test $? -ne 0; then
		printf "Failed to load the target module: ${TARGET_NAME1}\n"
		cleanupAll
		exit 1
	fi

	checkOutputStrings "${EXPECTED_LOAD_STRING}" "<none>"

	@RMMOD@ "${TARGET_NAME1_ACTUAL}"
	if test $? -ne 0; then
		printf "Failed to unload the target module: ${TARGET_NAME1}\n"
		cleanupAll
		exit 1
	fi
	
	checkOutputStrings "${EXPECTED_LOAD_STRING}" "${EXPECTED_UNLOAD_STRING}"
	
	# Instruct KEDR to look for another target module
	echo "${TARGET_NAME2}" > "/sys/module/@KEDR_CORE_NAME@/parameters/target_name"
    if test $? -ne 0; then
        printf "Failed to set target name.\n"
        cleanupAll
        exit 1
    fi
	
	EXPECTED_LOAD_STRING="${TARGET_NAME2_ACTUAL}"
	
	@INSMOD@ "${TARGET_MODULE2}"
	if test $? -ne 0; then
		printf "Failed to load the target module: ${TARGET_NAME2}\n"
		cleanupAll
		exit 1
	fi
	
	checkOutputStrings "${EXPECTED_LOAD_STRING}" "${EXPECTED_UNLOAD_STRING}"
	
	EXPECTED_UNLOAD_STRING="${TARGET_NAME2_ACTUAL}"
	
	@RMMOD@ "${TARGET_NAME2_ACTUAL}"
	if test $? -ne 0; then
		printf "Failed to unload the target module: ${TARGET_NAME2}\n"
		cleanupAll
		exit 1
	fi
	
	checkOutputStrings "${EXPECTED_LOAD_STRING}" "${EXPECTED_UNLOAD_STRING}"
	
	# Clear the target specification. KEDR should no longer watch for any
	# target to load.
	echo "none" > "/sys/module/@KEDR_CORE_NAME@/parameters/target_name"
    if test $? -ne 0; then
        printf "Failed to clear target specification.\n"
        cleanupAll
        exit 1
    fi
    
    # Load and unload the first target again and check that the payload 
    # has not been notified.
    @INSMOD@ "${TARGET_MODULE1}" 
	if test $? -ne 0; then
		printf "Failed to load the target module: ${TARGET_NAME1}\n"
		cleanupAll
		exit 1
	fi
	
	@RMMOD@ "${TARGET_NAME1_ACTUAL}"
	if test $? -ne 0; then
		printf "Failed to unload the target module: ${TARGET_NAME1}\n"
		cleanupAll
		exit 1
	fi
	
	checkOutputStrings "${EXPECTED_LOAD_STRING}" "${EXPECTED_UNLOAD_STRING}"
}

########################################################################
# main
########################################################################
WORK_DIR=${PWD}

if test $# -ne 2; then
	printf "Usage: sh test_change_target.sh <target_dir1> <target_dir2>\n"
	exit 1
fi

TARGET_DIR1=$1
TARGET_DIR2=$2

TARGET_NAME1="test_${TARGET_DIR1}"
TARGET_NAME1_ACTUAL=$(echo "${TARGET_NAME1}" | tr '-' '_')
TARGET_MODULE1="${TARGET_DIR1}/${TARGET_NAME1}.ko"

TARGET_NAME2="test_${TARGET_DIR2}"
TARGET_NAME2_ACTUAL=$(echo "${TARGET_NAME2}" | tr '-' '_')
TARGET_MODULE2="${TARGET_DIR2}/${TARGET_NAME2}.ko"

printf "Target modules: ${TARGET_MODULE1}, ${TARGET_MODULE2}\n"

PAYLOAD_NAME="test_basics_payload"
PAYLOAD_MODULE="payload/${PAYLOAD_NAME}.ko"

################################
checkPrereqs
doTest
cleanupAll

# test passed
exit 0
